package main

import (
	"fmt"
	"strings"
)

/**
函数式编程与闭包
- 概念

- 应用场景
1、闭包: 函数内部引用了其它函数内部变量的函数，用于需要外部函数变量参与计算的场景
2、中间价: 在不影响原函数的功能下增加额外的功能
3、函数类型对象: 为函数拓展功能，且该功能需要该函数参与计算

- 陷阱
1、for循环中使用闭包可能会出现问题
*/

func main() {
	fmt.Println(intSum(10, 20))        // 30
	fmt.Println(changeSum())           // 0
	fmt.Println(changeSum(10))         // 10
	fmt.Println(changeSum(10, 20))     // 30
	fmt.Println(changeSum(10, 20, 30)) // 60

	var f = addSum(10)
	fmt.Println(f(20)) // 30

	var g = makeSuffixFunc(".txt")
	fmt.Println(g("沙河娜扎")) // 沙河娜扎.txt

	var h, j = calc(10)
	fmt.Println(h(20)) // 30
	fmt.Println(j(10)) // 0

	res := deferFunc(10, 20) //  3 2 1
	fmt.Println("res:", res) // "凯尔特人必胜"
}

// 1 返回值命名
func intSum(x, y int) (res int) {
	res = x + y
	return
}

// 2 可变参数
func changeSum(x ...int) int {
	sum := 0
	for _, v := range x {
		sum += v
	}
	return sum
}

// 3 闭包函数进阶一
func addSum(x int) func(int) int {
	return func(y int) int {
		x += y
		return x
	}
}

// 4 闭包函数进阶二
func makeSuffixFunc(suffix string) func(string) string {
	return func(name string) string {
		if !strings.HasSuffix(name, suffix) {
			return name + suffix
		}
		return name
	}
}

// 5 闭包函数进阶三
func calc(a int) (func(int) int, func(int) int) {
	add := func(b int) int {
		return a + b
	}

	sub := func(c int) int {
		return a - c
	}

	return add, sub
}

// 6 defer
/**1.为什么要使用defer?
在函数中，程序员需要经常创建资源(比如连接数据库、文件句柄、锁等)，为了在函数执行完毕后及时的释放资源，go的设计者提供了defer(延迟机制)
*/
/**2.运行规则
2.0defer只能是函数调用
2.1当代码运行时，遇到defer关键字，暂不执行，会将defer后面的代码块压入到独立的栈中(defer栈)
2.2当函数或方法执行完毕时，再从defer栈中按照 ·先进后出· 执行(队列，延迟执行)
2.3deder将语句放入栈中时，也会将相关的值放入栈中
*/
/** 3.return与defer执行顺序：先return 再defer */
func deferFunc(num1, num2 int) string {
	fmt.Println("strat")             // 1: start
	defer fmt.Println("num1:", num1) // 3: 10
	defer fmt.Println("num2:", num2) // 2: 20
	defer func() {
		fmt.Println("1") // 8: 1
	}()

	defer func() {
		fmt.Println("2") // 7: 2
	}()

	defer func() {
		fmt.Println("3") // 6: 3
	}()
	num1++
	num2++
	fmt.Println("num1+num2:", num1+num2) // 4: 32
	fmt.Println("end")                   // 5: end
	return "凯尔特人必胜"
}

// defer最佳实践一：关闭文件资源
// func deferOpenFile(filepath string) {
// 	file = openFile(filepath)
// 	defer file.close()
//  其他代码
// }

// defer最佳实践二：关闭数据库资源
// func deferOpenFile() {
// 	conn = openDataBase()
// 	defer conn.close()
//  其他代码
// }
